package org.bulu.project.service.video.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.bulu.project.common.result.Result;
import org.bulu.project.common.result.ResultCode;
import org.bulu.project.service.video.service.CommentService;
import org.bulu.project.system.util.RedisUtil;
import org.bulu.project.system.mapper.VideoStatsMapper;
import org.bulu.project.system.model.dto.CommentDTO;
import org.bulu.project.system.mapper.CommentMapper;
import org.bulu.project.system.mapper.VideoMapper;
import org.bulu.project.system.model.dto.CommentContentDTO;
import org.bulu.project.system.model.entity.Comment;
import org.bulu.project.system.model.entity.VideoStats;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.bulu.project.system.model.entity.Video;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.stream.Collectors;

import static java.util.concurrent.TimeUnit.DAYS;


@Service
public class CommentServiceImpl implements CommentService {
    private static final Logger log = LoggerFactory.getLogger(CommentServiceImpl.class);
    @Autowired
    private CommentMapper commentMapper;
    @Autowired
    private VideoMapper VideoMapper;
    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private VideoStatsMapper videoStatsMapper;
    @Autowired
    @Qualifier("taskExecutor")
    private Executor taskExecutor;

    /**
     * 发送评论，字数不得大于2000或为空
     * @param commentDTO  评论dto
     * @return  result
     */
    @Override
    @Transactional
    public Result addComment(CommentDTO commentDTO) {
        try {
            if (commentDTO.getContent() == null || commentDTO.getContent().length() == 0 || commentDTO.getContent().length() > 2000)
                return Result.failed();
            Comment comment = new Comment();
            comment.setVid(commentDTO.getVId());
            comment.setUid(commentDTO.getUId());
            comment.setRootId(commentDTO.getRootId());
            comment.setParentId(commentDTO.getParentId());
            comment.setToUserId(commentDTO.getToUserId());
            comment.setContent(commentDTO.getContent());
            comment.setLove(commentDTO.getLove());
            comment.setBad(commentDTO.getBad());
            comment.setCreateTime(new Date());
            commentMapper.insert(comment);
            CompletableFuture.runAsync(() -> {
                // 如果是第一层根评论，则加入 "comment_video:" + vid 的 zset 中
                if (commentDTO.getParentId() == 0) {
                    redisUtil.zset("comment_video:" + commentDTO.getVId(), comment.getId());
                    //创建redis里的点赞缓存
                    createLikeAndDislikeCache(comment);
                } else {
                    // 如果不是第一层根评论，则加入 "comment_reply:" + rootId 的 zset 中
                    redisUtil.zset("comment_reply:" + commentDTO.getRootId(), comment.getId());
                    // 不是自己回复自己
                    if (!comment.getToUserId().equals(comment.getUid())) {
                        redisUtil.zset("reply_zset:" + comment.getToUserId(), comment.getId());
                        // 待补充： 添加未读消息 通知操作 放入mq

                    }
                    //创建redis里的点赞缓存
                    createLikeAndDislikeCache(comment);
                }
            }, taskExecutor).exceptionally(e -> {
                log.error("异步任务执行异常", e);
                throw new RuntimeException(e);
            });
            //更新视频评论 + 1 操作
            updateVideoCommentCount(commentDTO.getVId(),1);
        } catch (Exception e) {
            log.error("添加数据失败", e);
            return Result.failed();
        }
        return Result.success(ResultCode.SUCCESS);
    }
    private void createLikeAndDislikeCache(Comment comment) {
        // 创建点赞的 Redis 缓存
        redisUtil.zset("comment_like:" + comment.getId(), 0L);
        // 创建点踩的 Redis 缓存
        redisUtil.zset("comment_dislike:" + comment.getId(), 0L);
    }
    /**
     * 更新视频评论数
     * @param vid
     * @param commentDelta
     */
    private void updateVideoCommentCount(Integer vid, int commentDelta) {
        VideoStats videoStats = videoStatsMapper.queryById(vid);
        //此步后续加前端后可以删除判断逻辑
        if (videoStats == null) {
            Result.failed("视频不存在，无法发表评论");
        } else {
            videoStats.setComment(videoStats.getComment() + commentDelta);//更新评论计数
        }
        videoStatsMapper.update(videoStats);
        //更新redis中redis缓存中的点赞量
        redisUtil.delValue("videoStats:" + vid);
        CompletableFuture.runAsync(() -> redisUtil.setExValue("videoStats:" + videoStats.getVid(), videoStats,30, DAYS), taskExecutor);

    }
    /**
     * 删除评论
     * @param id    评论id
     * @param uid   当前用户id
     * @param isAdmin   是否是管理员
     * @return  result
     */
    @Override
    @Transactional
    public Result deleteComment(Integer id, Integer uid, boolean isAdmin) {  //isAdmin后续通过权限校验
        Comment comment = commentMapper.queryById(id);
        if (comment == null) {
            return Result.failed("评论不存在");
        }
        //后续 加入权限认证 不用自己判断isAdmin
        Video video = VideoMapper.queryVideoByVid(comment.getVid());
        if (comment.getUid().equals(uid) || isAdmin || video.getUid().equals(uid)) {
            commentMapper.updateDeleteStatus(id, 1);
            if (comment.getParentId() == 0) {
                // 递归删除根评论的所有直接回复及其子回复
                int totalCommentsDeleted = deleteAllReplies(comment.getUid(), comment.getVid()); //////
                // 更新视频评论数
                updateVideoCommentCount(comment.getVid(), -totalCommentsDeleted);
                // 删除redis缓存
                redisUtil.zsetDelMember("comment_video:" + comment.getVid(), String.valueOf(comment.getId()));
                redisUtil.delValue("comment_reply:" + comment.getId());
            } else {
                // 删除redis缓存
                redisUtil.zsetDelMember("comment_reply:" + comment.getRootId(), String.valueOf(comment.getId()));
                // 更新视频评论数
                updateVideoCommentCount(comment.getVid(), -1);
            }
            return Result.success(ResultCode.SUCCESS);
        } else {
            return Result.failed(ResultCode.ACCESS_UNAUTHORIZED);
        }
    }
    private int deleteAllReplies(Integer rootId, Integer vid) {
        // 查询根评论的所有直接回复
        Set<Object> replyIds = redisUtil.zgetAllMembers("comment_reply:" + rootId, RedisUtil.REDIS_DEFAULT_EXPIRE_TIME);
        int totalCommentsDeleted = 1;//包含根评论本身
        // 遍历直接回复
        for (Object replyIdObj : replyIds) {
            Integer replyId = (Integer) replyIdObj;
            commentMapper.updateDeleteStatus(replyId, 1);
            // 删除回复评论在 Redis 中的记录
            redisUtil.zsetDelMember("comment_reply:" + rootId, replyId);
            // 获取回复评论的详情
            Comment reply = commentMapper.queryById(replyId);
            // 删除 reply_zset 中的记录
            if (reply != null) {
                redisUtil.zsetDelMember("reply_zset:" + reply.getToUserId(), String.valueOf(replyId));
            }
            // 递归删除子回复
            int subCommentsDeleted = 0;
            if (reply != null) {
                // 查找子评论
                subCommentsDeleted = deleteSubCommentsByParentId(replyId, vid);
            }
            totalCommentsDeleted += subCommentsDeleted + 1; // 包括当前回复
        }
        return totalCommentsDeleted;
    }
    // 新增方法: 通过 parentId 删除子评论
    private int deleteSubCommentsByParentId(Integer parentId, Integer vid) {
        // 查询以该 parentId 为 uid 的所有评论
        List<Comment> subComments = commentMapper.queryByParentId(parentId);
        int totalCommentsDeleted = 0;

        for (Comment subComment : subComments) {
            // 进行逻辑删除
            commentMapper.updateDeleteStatus(subComment.getId(), 1);
            // 删除子评论在 Redis 中的记录
            redisUtil.zsetDelMember("comment_reply:" + subComment.getRootId(), subComment.getId());
            // 删除 reply_zset 中的记录
            if (subComment != null) {
                redisUtil.zsetDelMember("reply_zset:" + subComment.getToUserId(), String.valueOf(subComment.getId()));
            }
            // 递归删除子评论的子评论
            int subSubCommentsDeleted = 0;
            if (subComment != null) {
                subSubCommentsDeleted = deleteSubCommentsByParentId(subComment.getId(), vid);
            }
            totalCommentsDeleted += subSubCommentsDeleted + 1; // 包括当前子评论
        }
        return totalCommentsDeleted;
    }

    /**
     * 获取所有评论
     * @param vid 视频id
     * @param sortChoose 0为按时间排序，1为按点赞数排序
     * @return List<CommentContentDTO>
     */
    @Override
    public List<CommentContentDTO> getAllComments(Integer vid, Integer sortChoose) {
        List<CommentContentDTO> comments = commentMapper.getAllComments(vid);
        List<CommentContentDTO> sortedComments;
        if (sortChoose==1) {
            // 使用Stream API进行排序
            sortedComments = comments.stream()
                    .sorted(Comparator.comparingInt(CommentContentDTO::getLove).reversed())
                    .collect(Collectors.toList());

        }else{
             sortedComments= comments.stream()
                    .sorted(Comparator.comparing(CommentContentDTO::getCreateTime).reversed())
                    .collect(Collectors.toList());
        }
        return sortedComments;
    }
    /**
     *查找父评论及其子评论
     * @param comments
     * @param sortChoose 0为按时间排序，1为按点赞数排序
     * @return List<CommentContentDTO>
     */
    @Override
    public PageInfo findParent(List<CommentContentDTO> comments, Integer sortChoose,Integer currentCommentPage) {
        // 构建一个映射，快速查找它的子评论
        Map<Integer, CommentContentDTO> commentMap = new HashMap<>();
        List<CommentContentDTO> rootComments = new ArrayList<>();
        // 建立评论映射
        for (CommentContentDTO comment : comments) {
            commentMap.put(comment.getUId(), comment);
            if (comment.getParentId() == 0) {
                rootComments.add(comment);
            }
        }
        // 处理每个根评论及其子评论
        for (CommentContentDTO rootComment : rootComments) {
            findChildren(rootComment, commentMap, sortChoose); // 添加排序参数
        }
        PageHelper.startPage(currentCommentPage, 10);
        PageInfo page = new PageInfo<>(rootComments);
        return page;
    }
    private void findChildren(CommentContentDTO parent, Map<Integer, CommentContentDTO> commentMap, Integer sortChoose) {
        // 找出直接子级
        List<CommentContentDTO> comments = new ArrayList<>();
        for (CommentContentDTO comment : commentMap.values()) {
            if (comment.getParentId() == parent.getUId()) {
                comments.add(comment);
            }
        }
        // 对子评论进行排序
        if (sortChoose==1) {
            List<CommentContentDTO> sortedComments = comments.stream()
                    .sorted(Comparator.comparingInt(CommentContentDTO::getLove).reversed())
                    .collect(Collectors.toList());
            comments = sortedComments;
        }else {
            List<CommentContentDTO> sortedComments = comments.stream()
                    .sorted(Comparator.comparing(CommentContentDTO::getCreateTime).reversed())
                    .collect(Collectors.toList());
            comments = sortedComments;
        }
        // 递归处理子评论的子评论
        for (CommentContentDTO comment : comments) {
            findChildren(comment, commentMap, sortChoose); // 传递排序参数
        }
        parent.setChildren(comments);
    }
    /**
     * 点赞或者点踩评论
     * @param id 评论id
     * @param userId 用户id
     * @param isLike 是否点赞 true点赞 false点踩
     */
    @Override
    @Transactional
    public Result likeOrDislikeComment(Integer id, Integer userId, boolean isLike) {
        try {
            // 1. 判断用户是否已经点赞或者点踩过该评论
            boolean isLiked = redisUtil.zsetIsMember("comment_like:" + id, userId);
            boolean isDisliked = redisUtil.zsetIsMember("comment_dislike:" + id, userId);
            //已经点赞过现在要点踩  则先取消点赞
            if (isLiked && !isLike ){
                cancelLikeOrDislike(id, userId, true); // 取消点赞
            }
            //已经点踩过现在要点赞  则先取消点踩
            else if (isDisliked && isLike) {
                cancelLikeOrDislike(id, userId, false); // 取消点踩
            }
            //如果已经点赞或者点踩过，则取消原来的点赞或者点踩
            if ((isLiked && isLike) || (isDisliked && !isLike)) {
                cancelLikeOrDislike(id, userId, isLike);
            } else {
                //如果没有点赞或者点踩过，则新增点赞或者点踩
                addLikeOrDislike(id, userId, isLike);
            }
            //更新评论的点赞量或者点踩量
            updateCommentLikeOrDislikeCount(id, isLike);
        } catch (Exception e) {
            return Result.failed("点赞或点踩失败");
        }
        return Result.success();
    }
    //取消点赞或点踩
    private void cancelLikeOrDislike(Integer id, Integer userId, boolean isLike) {
        if (isLike) {
            // 从Redis中删除点赞记录
            redisUtil.zsetDelMember("comment_like:" + id, userId);
        } else {
            // 从Redis中删除点踩记录
            redisUtil.zsetDelMember("comment_dislike:" + id, userId);
        }
    }
    //添加点赞或点踩
    private void addLikeOrDislike(Integer id, Integer userId, boolean isLike) {
        if (isLike) {
            // 向Redis中添加点赞记录
            redisUtil.zsetWithScore("comment_like:" + id, userId,RedisUtil.REDIS_DEFAULT_EXPIRE_TIME);
        } else {
            // 向Redis中添加点踩记录
            redisUtil.zsetWithScore("comment_dislike:" + id, userId,RedisUtil.REDIS_DEFAULT_EXPIRE_TIME);
        }
    }
    //更新评论的点赞量或者点踩量
    private void updateCommentLikeOrDislikeCount(Integer id, boolean isLike) {
        // 从Redis中获取最新的点赞或点踩数量
        long likeCount = redisUtil.zCard("comment_like:" + id);
        long dislikeCount = redisUtil.zCard("comment_dislike:" + id);
        // 更新评论的点赞量或者点踩量
        commentMapper.updateLove(id, (int) likeCount);
        commentMapper.updateDislove(id, (int) dislikeCount);
    }
}
